home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / processes / just finder / just finder.c next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  12.0 KB  |  345 lines

  1. /*
  2.     File:        Just Finder.c
  3.  
  4.     Contains:    A System 7 application that kills all processes with faces except the Finder.
  5.                 Handy for working with Fonts or any other component where you get that blasted
  6.                 Finder alert saying "Close everything but the Finder before doing this."
  7.     
  8.     Written by: Matt Deatherage    
  9.  
  10.     Copyright:    Copyright © 1993-1999 by Apple Computer, Inc., All Rights Reserved.
  11.  
  12.                 You may incorporate this Apple sample source code into your program(s) without
  13.                 restriction. This Apple sample source code has been provided "AS IS" and the
  14.                 responsibility for its operation is yours. You are not permitted to redistribute
  15.                 this Apple sample source code as "Apple sample source code" after having made
  16.                 changes. If you're going to re-distribute the source, we require that you make
  17.                 it clear in the source that the code was descended from Apple sample source
  18.                 code, but that you've made changes.
  19.  
  20.     Change History (most recent first):
  21.                 7/26/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  22.  
  23. */
  24.  
  25. /*------ Includes ------------------------------------------------------------------------*/
  26. #include <quickdraw.h>
  27. #include <fonts.h>
  28. #include <windows.h>
  29. #include <menus.h>
  30. #include <textedit.h>
  31. #include <dialogs.h>
  32. #include <errors.h>
  33. #include <types.h>
  34. #include <string.h>
  35. #include <processes.h>
  36. #include <Events.h>
  37. #include <AppleEvents.h>
  38.  
  39. /*------ Prototypes ----------------------------------------------------------------------*/
  40.  
  41. void InstallAEHandlers(void);
  42. pascal OSErr oappHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
  43. pascal OSErr odocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
  44. pascal OSErr pdocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
  45. pascal OSErr quitHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
  46. OSErr CheckRequiredParms(AppleEvent *theAppleEvent);
  47. Boolean ShouldWeKill(ProcessInfoRec* processInfo);
  48. void KillThemAll(void);
  49.  
  50. /*------ main ----------------------------------------------------------------------------*/
  51.  
  52. void main()
  53.  
  54. {
  55.  
  56. GrafPort myPort;
  57.  
  58.  
  59.     InitGraf((Ptr) &qd.thePort);
  60.     OpenPort((GrafPtr) &myPort);
  61.     InitFonts();
  62.     InitWindows();
  63.     InitMenus();
  64.     TEInit();
  65.     InitDialogs(nil);
  66.     InitCursor();
  67.     
  68.     KillThemAll();
  69.     
  70.  
  71. } /* main */
  72.  
  73. /*******************************************************************************************
  74. *
  75. * According to the rules, all applications that say they're high-level event aware must
  76. * respond to the four required Apple events.  This application has no user interface and
  77. * doesn't deal with documents at all, nor will it quit prematurely.  However, rules is
  78. * rules, so we install four very minimal required event handlers.  The ones with parameters
  79. * return an OSErr that indicates whether all the parameters were read (they weren't, if
  80. * there were any, so it usually returns errAEEventNotHandled).
  81. *
  82. *******************************************************************************************/
  83.  
  84.  
  85.  
  86. /*------ InstallAEHandlers ---------------------------------------------------------------*/
  87.  
  88. void InstallAEHandlers(void)
  89. {
  90.  
  91.     AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,NewAEEventHandlerProc(oappHandler),
  92.                           0,false);
  93.     AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,NewAEEventHandlerProc(odocHandler),
  94.                           0,false);
  95.     AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,NewAEEventHandlerProc(pdocHandler),
  96.                           0,false);
  97.     AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,NewAEEventHandlerProc(quitHandler),
  98.                           0,false);
  99. }
  100.  
  101. /*******************************************************************************************
  102. *
  103. * CheckRequiredParams is a common Apple event utility routine -- it returns noErr if
  104. * someone has retrieved all the required parameters from the Apple event passed.  If there
  105. * are still some left, it returns errAEEventNotHandled.
  106. *
  107. * The check is simple -- look for the "missed keyword" attribute.  If there isn't one,
  108. * everything is fine.
  109. *
  110. *******************************************************************************************/
  111.  
  112. /*------ CheckRequiredParms ---------------------------------------------------------------*/
  113.  
  114. OSErr CheckRequiredParms(AppleEvent *theAppleEvent)
  115. {
  116.  
  117.     OSErr myErr;
  118.     DescType attrType;
  119.     Size attrSize;
  120.     
  121.     myErr = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
  122.                               &attrType, 0L, 0, &attrSize);
  123.                               
  124.     if (myErr == errAEDescNotFound)
  125.         myErr = noErr;
  126.         
  127.     if (myErr == noErr)
  128.         myErr = errAEEventNotHandled;
  129.         
  130.     return(myErr);
  131.     
  132. }
  133.  
  134. /*******************************************************************************************
  135. *
  136. * The core AE handlers don't do very much except return errors saying "I didn't do that."
  137. *
  138. *******************************************************************************************/
  139.  
  140. /*------ The core AE handlers -------------------------------------------------------------*/
  141.  
  142. pascal OSErr oappHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  143. {
  144.     #pragma unused(reply,refCon)
  145.  
  146.     return(CheckRequiredParms(theAppleEvent));
  147.  
  148. }
  149.  
  150. pascal OSErr odocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  151. {
  152.     #pragma unused(theAppleEvent,reply,refCon)
  153.     return(errAEEventNotHandled);
  154.  
  155. }
  156.  
  157. pascal OSErr pdocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  158. {
  159.     #pragma unused(theAppleEvent,reply,refCon)
  160.     return(errAEEventNotHandled);
  161.  
  162. }
  163.  
  164. pascal OSErr quitHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  165. {
  166.     #pragma unused(reply,refCon)
  167.     return(CheckRequiredParms(theAppleEvent));
  168.  
  169. }
  170.  
  171. /*******************************************************************************************
  172. *
  173. * ShouldWeKill is the routine that decides if a given process, as specified by a
  174. * ProcessInfoRec, should be killed.  We kill all foreground processes that aren't this
  175. * application or the Finder.  The ProcessInfoRec must be fully initialized by a routine
  176. * very similar to GetProcessInfo or else this routine will probalby do very strange things.
  177. *
  178. *******************************************************************************************/
  179.  
  180. /*------ ShouldWeKill ---------------------------------------------------------------------*/
  181.  
  182. Boolean ShouldWeKill(ProcessInfoRec* processInfo)
  183. {
  184.     
  185.     OSErr myErr;
  186.     ProcessSerialNumber thisProcess;
  187.     Boolean twinProcesses;
  188.     
  189.     thisProcess.highLongOfPSN = 0;
  190.     thisProcess.lowLongOfPSN = kCurrentProcess;        // set up the PSN for this application
  191.     
  192.     myErr = SameProcess(&(processInfo->processNumber), &thisProcess, &twinProcesses);
  193.                                                     // sets up twinProcesses to contain TRUE
  194.                                                     // if the passed process and this one are
  195.                                                     // one and the same
  196.     
  197.     if (!(twinProcesses) &&                            // if this isn't _this_ process and
  198.        !(processInfo->processSignature == 'MACS' && processInfo->processType == 'FNDR') &&
  199.                                                        // if it's not the Finder and
  200.        !(processInfo->processMode & modeOnlyBackground))
  201.                                                        // if it's not background-only then
  202.        {
  203.         return true;                                // Yup, kill it, or do other things to it here.
  204.         } else {
  205.         return false;                                // Nope, it's been spared, or do other things.
  206.        }
  207.  
  208. }
  209.  
  210. /*******************************************************************************************
  211. *
  212. * From looking at published sample code such as ProcDoggie and KillEveryoneButMe (1.0.1),
  213. * you'd think killing a process is a relatively straight-forward thing to do.
  214. *
  215. * Think again.
  216. *
  217. * This took quite some time to figure out, thanks to obscure errors like -603 coming back
  218. * from the Process Manager at strange times.  Here's what I learned, some of which is kind
  219. * of obvious and some of which isn't.
  220. *
  221. * 1.  Don't call GetNextProcess on a process that you've just killed.  It tends to confuse
  222. *     things.  (duh...)  Instead, once we kill a process, we start over at the beginning
  223. *      of the process list, skipping those processes we don't wish to kill.  You know
  224. *      you're done when you hit the end of the process list without killing any processes.
  225. *
  226. * 2.  After killing a process, the Process Manager expects you to keep processing events.
  227. *     Remember the three calls to EventAvail() you have to do at the beginning of most
  228. *      real applications before you become the front process?  In similar ways, the Process
  229. *      Manager might become confused if you're firing off lots of kill events but never
  230. *      call WaitNextEvent to get any.
  231. *
  232. *      So how many times should you call WaitNextEvent?  I've seen numbers from 4 to 25,
  233. *      and they didn't necessarily work for me.  Instead, we call WaitNextEvent until we
  234. *      get a null event, the system's surefire way of indicating it's not doing anything
  235. *      major at this time.  If we get a high-level event, we call AEProcessAppleEvent to
  236. *      follow the rules -- but we ignore other events.
  237. *
  238. *      Note that this might not work for you if you're an application with windows and
  239. *     the like, because you could get an update event.  If you don't process the update
  240. *      event, it won't go away.  This application has no windows and doesn't have to
  241. *      worry about that.
  242. *
  243. *******************************************************************************************/
  244.  
  245.  
  246. /*------ KillThemAll ----------------------------------------------------------------------*/
  247.  
  248. void KillThemAll(void)
  249. {
  250.  
  251.     ProcessSerialNumber theProcess;
  252.     ProcessInfoRec ourProcessInfo;
  253.     OSErr myErr;
  254.     Str31 theProcessName;
  255.     FSSpec theProcessSpec;
  256.     AppleEvent ourQuitEvent, ourReplyEvent;
  257.     AEAddressDesc ourPSNDesc;
  258.     EventRecord theEvent;
  259.     
  260.     // set up the ourProcessInfo record to point to space we've allocated...
  261.     
  262.     ourProcessInfo.processInfoLength = sizeof(ProcessInfoRec);
  263.     ourProcessInfo.processName = (StringPtr)&theProcessName;
  264.     ourProcessInfo.processAppSpec = &theProcessSpec;
  265.     
  266.     theProcess.highLongOfPSN = 0;
  267.     theProcess.lowLongOfPSN = kNoProcess;        // return the first process
  268.  
  269.     while (true) 
  270.         {
  271.         
  272.         // Call WaitNextEvent until we get a null event, meaning all is calm
  273.         
  274.         do {
  275.             WaitNextEvent(everyEvent, &theEvent, 600L, 0L);
  276.             if (theEvent.what == kHighLevelEvent)
  277.                 AEProcessAppleEvent(&theEvent);
  278.             } while (theEvent.what != nullEvent);
  279.             
  280.         myErr = GetNextProcess(&theProcess);
  281.         if (myErr == procNotFound)    
  282.             break;                                // if no process, we're done!
  283.  
  284.         myErr = GetProcessInformation(&theProcess,&ourProcessInfo);
  285.         // Check to see if we want to kill this process
  286.             
  287.         if (ShouldWeKill(&ourProcessInfo))
  288.             {
  289.         
  290.             // Create a process serial number descriptor for this process
  291.             
  292.             myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&theProcess,
  293.                                  sizeof(theProcess), &ourPSNDesc);
  294.             if (myErr == noErr)
  295.                 {
  296.                 
  297.                 // Create the 'quit' Apple event for this process.  This might return error
  298.                 // -603 for desk accessories if you don't call WaitNextEvent enough times
  299.                 // like above.
  300.                 
  301.                 myErr = AECreateAppleEvent(kCoreEventClass,kAEQuitApplication, &ourPSNDesc,
  302.                                            kAutoGenerateReturnID, kAnyTransactionID, &ourQuitEvent);
  303.                 if (myErr == noErr)
  304.                     {
  305.                     
  306.                     // send the event 
  307.                     
  308.                     myErr = AESend(&ourQuitEvent, &ourReplyEvent, kAENoReply,
  309.                                    kAENormalPriority, kNoTimeOut, 0L, 0L);
  310.                                    
  311.                     if (myErr == noErr)
  312.                         {
  313.                         
  314.                         // Sadly, some applications won't respond to Apple events and do
  315.                         // what they're supposed to do until they're brought to the front,
  316.                         // so we do that, and continue our work in the background.
  317.  
  318.                         SetFrontProcess(&theProcess);
  319.                         
  320.                         }
  321.  
  322.                         // dispose of the event only if we succesfully created it.
  323.                         
  324.                         myErr = AEDisposeDesc(&ourQuitEvent);
  325.                     }
  326.                 
  327.                 // dispose of the descriptor only if we succesfully created it.
  328.                 
  329.                 myErr = AEDisposeDesc(&ourPSNDesc);
  330.             
  331.                 }
  332.             
  333.             // Now, since we killed a process, we don't want to call GetNextProcess
  334.             // on the one we just eliminated!  (That would be bad.)  So we reset our
  335.             // process record to contain the serial number of "no process", so the
  336.             // next call to GetProcessInfo returns the first process, and we start
  337.             // all over again.
  338.             
  339.             theProcess.highLongOfPSN = 0;
  340.             theProcess.lowLongOfPSN = kNoProcess;        // return to the first process
  341.             }
  342.         }
  343. }
  344.     
  345.